﻿using UnityEngine;
using System.Collections;

using System.Collections.Generic;
using System.IO;
using System.Text;
using System;

public class OutLog : MonoBehaviour
{
    [System.Serializable]
    public class OutLogConfig
    {
        /// <summary>
        /// 总的开关 //
        /// The is can print.
        /// </summary>
        public bool isCanPrint = true;
        public bool isCanWrite = true;

        public bool isPrintLog = false;
        public bool isWriteLog = true;
        public bool isPrintWarning = false;
        public bool isWriteWarning = true;
        public bool isPrintError = true;
        public bool isWriteError = true;
        public bool isPrintException = true;
        public bool isWriteException = true;
    }

    public OutLogConfig outLogConfig;

    static List<string> mLines = new List<string>();		// 屏幕上的 //
    static List<string> mWriteTxt = new List<string>();     // 写入文件里的 //

    private string outLogPath = "";                         // Log的输出路径 //
    private string outLogName = "OutLog.txt";               // Log的文件名 //

    bool isInitComplete;

    void Awake()
    {
        // 初始化一下相关路径 //
        outLogPath = Application.temporaryCachePath + "/OutLog/";

        // 创建Log文件夹 //
        if(!Directory.Exists(outLogPath))
        {
            Directory.CreateDirectory(outLogPath);
        }

        // 如果之前有Log, 根据时间重命名, 保存起来 //
        if(System.IO.File.Exists(outLogPath + outLogName))
        {
            File.Copy(outLogPath + outLogName, outLogPath + "OutLog_" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".txt");
            File.Delete(outLogPath + outLogName);
        }

        // 在这里做一个Log的监听 //
        Application.logMessageReceived += SystemLogHandle;

        isInitComplete = true;

        // 输出一些路径以备不时之需 //
        Debug.Log("Application.temporaryCachePath:" + Application.temporaryCachePath);
        Debug.Log("Application.dataPath:" + Application.dataPath);
        Debug.Log("Application.persistentDataPath:" + Application.persistentDataPath);
        Debug.Log("Application.streamingAssetsPath:" + Application.streamingAssetsPath);
    }

    void OnDestroy()
    {
        Application.logMessageReceived -= SystemLogHandle;
    }

    void Update()
    {
        if(!outLogConfig.isCanWrite)
        {
            if(mWriteTxt.Count > 0)
            {
                mWriteTxt.Clear();
            }
            return;
        }

        //因为写入文件的操作必须在主线程中完成, 所以在Update中, 写入文件。
        if(mWriteTxt.Count > 0)
        {
            string[] temp = null;
            try
            {
                temp = mWriteTxt.ToArray();
                foreach(string t in temp)
                {
                    using(StreamWriter writer = new StreamWriter(outLogPath + outLogName, true, Encoding.UTF8))
                    {
                        writer.WriteLine(DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff") + "---" + t + "\n");
                    }
                    mWriteTxt.Remove(t);
                }
            }
            catch(Exception ex)
            {
                Debug.LogError("OutLog---Update---catch(Exception ex)---1");
                Debug.LogException(ex);
                return;
            }
        }
    }

    /// <summary>
    /// Systems the log handle.
    /// </summary>
    /// <param name="logString">Log string.</param>
    /// <param name="stackTrace">Stack trace.</param>
    /// <param name="logType">Log type.</param>
    void SystemLogHandle(string logString, string stackTrace, LogType logType)
    {
        switch(logType)
        {
            case LogType.Log:
                if(outLogConfig.isPrintLog)
                {
                    PrintToScreen(logString + "\n" + stackTrace);
                }
                if(outLogConfig.isWriteLog)
                {
                    mWriteTxt.Add(logString + "\n" + stackTrace);
                }
                break;

            case LogType.Warning:
                if(outLogConfig.isPrintWarning)
                {
                    PrintToScreen(logString + "\n" + stackTrace);
                }
                if(outLogConfig.isWriteWarning)
                {
                    mWriteTxt.Add(logString + "\n" + stackTrace);
                }
                break;

            case LogType.Error:
                if(outLogConfig.isPrintError)
                {
                    PrintToScreen(logString + "\n" + stackTrace);
                }
                if(outLogConfig.isWriteError)
                {
                    mWriteTxt.Add(logString + "\n" + stackTrace);
                }
                break;

            case LogType.Exception:
                if(outLogConfig.isPrintException)
                {
                    PrintToScreen(logString + "\n" + stackTrace);
                }
                if(outLogConfig.isWriteException)
                {
                    mWriteTxt.Add(logString + "\n" + stackTrace);
                }
                break;
        }
    }

    /// <summary>
    /// 为了方便单元模块调试, 提供简单的直接调用方法, 一般调试完成之后应该把这个方法改为系统提供的方法(Debug) //
    /// Log the specified logString.
    /// </summary>
    /// <param name="logString">Log string.</param>
    public void Log(string logString)
    {
        PrintToScreen(logString);
        mWriteTxt.Add(logString);
    }

    //这里我把错误的信息保存起来，用来输出在手机屏幕上
    private void PrintToScreen(params object[] objs)
    {
        string text = "";
        for(int i = 0; i < objs.Length; ++i)
        {
            if(i == 0)
            {
                text += objs[i].ToString();
            }
            else
            {
                text += ", " + objs[i].ToString();
            }
        }
        if(Application.isPlaying)
        {
            if(mLines.Count > 20)
            {
                mLines.RemoveAt(0);
            }
            mLines.Add(text);
        }
    }

    void OnGUI()
    {
        if(!outLogConfig.isCanPrint)
        {
            if(mLines.Count > 0)
            {
                mLines.Clear();
            }
            return;
        }

        GUI.color = Color.red;
        for(int i = 0, imax = mLines.Count; i < imax; ++i)
        {
            GUILayout.Label(mLines[i]);
        }
    }
}